今天要學如何為元素加上事件,完成一個播放器。作者有提供播放器的HTML
跟CSS
內容,我只有增加HTML
的<input>
的title
屬性,剩下只會跟著作者做出播放器,程式碼是差不多的。
原本我想的是從body
裡面的容器player
去做點選,並且利用布林值當變數做開關,只要選到event.target
就執行切換,但這裡只要使用video.paused
屬性就能判斷這個影片有沒有在播放,再利用物件可以用任意修改中括號內容的特性,放入三元運算子的結果。
以這個想法再更換播放的圖示。
如果要用父元素body
點選子元素,我可能會再加上判斷event.target
是否為觸發的區塊。
const video = player.querySelector('.viewer');
const toggle = player.querySelector('.toggle');
function togglePlay(){
//video.paused判斷影片是否暫停
const method = video.paused ? 'play' : 'pause'
//如果是的話就播影片
video[method]();
}
function updateButton(){
//video.paused判斷影片是否暫停
const icon = this.paused ? '►' : '❚❚';
//如果是的話就換符號
toggle.textContent = icon;
}
video.addEventListener('click',togglePlay);
video.addEventListener('play',updateButton);
video.addEventListener('pause',updateButton);
toggle.addEventListener('click',togglePlay);
skip
按鍵有兩個,所以用forEach()
讓每個按鍵都加上監聽器,之後再使用屬性的預設值扣掉目前的秒數就行了,但是屬性的內容是字串,需要轉數值,也可以把Number()
換成parseFloat()
。
const skipButtons = player.querySelectorAll('[data-skip]');
function skip(){
video.currentTime += Number(this.dataset.skip);
}
skipButtons.forEach(button=>button.addEventListener('click',skip))
這邊我可能會想把兩個內容分開,但沒想到作者把兩個range
寫在一起,每次range
的值跟項目都不一樣,所以用this
就可以在觸發事件的當下選到元素,並且change
是在更動值的時候觸發,加上mousemove
的效果可以隨時更新值。
function handleRangeUpdate(){
video[this.name] = this.value;
}
ranges.forEach(range=>range.addEventListener('change',handleRangeUpdate))
ranges.forEach(range=>range.addEventListener('mousemove',handleRangeUpdate))
時間軸主要有兩件事,一是可以隨著播放影片,讓時間軸的寬度增加,二是在滑鼠拖曳的時候,可以讓時間軸的位置拉動到某個時間,讓影片從該時間繼續播放。
在試寫這個功能時,計算時間軸跟時間的比例有點難,但讓我感到最困難的是,我希望滑鼠拖曳的時候可以根據拖曳的距離計算時間軸的比例,可選不出比較好的距離或座標屬性跟計算方式,即使做出來的效果也不太好。
在計算滑鼠拖曳的距離與時間的比例,這邊是滑鼠的位移除以時間軸的整個長度,再乘上整支影片的長度,就能直接算出目前的時間,再回到timeupdate
事件更新。
function handleProgress(){
const percent = (video.currentTime/video.duration)*100
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(event){
//計算目前的時間
const scrubTime = (event.offsetX/progress.offsetWidth)*video.duration
video.currentTime = scrubTime;
}
video.addEventListener('timeupdate',handleProgress)
let mousedown = false;
progress.addEventListener('click',scrub)
progress.addEventListener('mousemove',(event)=>mousedown&&scrub(event))
progress.addEventListener('mousedown',()=>mousedown = true)
progress.addEventListener('mouseup',()=>mousedown = true)
作者在最後有讓大家去嘗試做一個按鈕觸發全螢幕,不過我不想改變現在介面的樣式,所以把事件綁在video
上面,讓畫面被點擊兩下就可以觸發全螢幕。原本寫了事件之後,想說從程式碼去修改尺寸,但是發現作者已經幫大家寫了一個樣式。
.player:fullscreen {
max-width: none;
width: 100%;
}
.player:-webkit-full-screen {
max-width: none;
width: 100%;
}
原本想說到底該怎麽觸發偽類,後來發現執行requestFullscreen()
方法就能觸發全螢幕。
function fullScreen(){
player.requestFullscreen()
}
video.addEventListener('dblclick',fullScreen)